package top.shenluw.tools.lyric

import com.google.gson.Gson
import java.io.InputStream
import java.io.InputStreamReader
import java.io.OutputStream
import java.io.OutputStreamWriter
import java.time.format.DateTimeFormatterBuilder


private val gson = Gson()

class NetEaseLyricConvert : LyricConvert() {
    private val titleRegex = "\\[ti:(.*)]".toRegex()
    private val singerRegex = "\\[ar:(.*)]".toRegex()
    private val albumRegex = "\\[al:(.*)]".toRegex()
    private val authorRegex = "\\[au:(.*)]".toRegex()
    private val byRegex = "\\[by:(.*)]".toRegex()
    private val timeRegex = "\\[(.*)](.*)".toRegex()

    override fun process(text: String): MutableList<TimeSlice> {
        val timelines = mutableListOf<TimeSlice>()
        text.split("\n")
            .filter { it.isNotBlank() }
            .map { it.trim() }
            .forEach {
                if (titleRegex.matches(it)) {
                    title = titleRegex.find(it)?.groupValues?.last()
                } else if (singerRegex.matches(it)) {
                    singer = singerRegex.find(it)?.groupValues?.last()
                } else if (authorRegex.matches(it)) {
                    author = authorRegex.find(it)?.groupValues?.last()
                } else if (albumRegex.matches(it)) {
                    album = albumRegex.find(it)?.groupValues?.last()
                } else if (byRegex.matches(it)) {
                    // nothing
                } else {
                    if (timeRegex.matches(it)) {
                        val groups = timeRegex.find(it)?.groupValues
                        if (groups != null) {
                            timelines.add(TimeSlice(groups[1].trim(), groups[2].trim()))
                        }
                    }
                }
            }

        return timelines
    }

}

class NetEaseLyricReader : LyricReader {
    override fun read(src: InputStream): MutableList<LyricInfo> {
        val map = gson.fromJson(InputStreamReader(src, Charsets.UTF_8), Map::class.java)

        val infos = mutableListOf<LyricInfo>()


        val lyricConvert = NetEaseLyricConvert()

        val lrcMap = map["lrc"] as Map<String, Any>?
        val tlyricMap = map["tlyric"] as Map<String, Any>?

        val lyric = lrcMap?.get("lyric")

        if (lyric != null) {
            val lyricInfo = LyricInfo()
            lyricInfo.timelines = lyricConvert.process(lyric as String)
            infos.add(lyricInfo)
        }

        val tlyric = tlyricMap?.get("lyric")
        if (tlyric != null) {
            val lyricInfo = LyricInfo()
            lyricInfo.tag = "tlyric"
            lyricInfo.timelines = lyricConvert.process(tlyric as String)
            infos.add(lyricInfo)
        }


        infos.forEach {
            it.album = lyricConvert.album
            it.author = lyricConvert.author
            it.singer = lyricConvert.singer
            it.title = lyricConvert.title
        }
        return infos

    }

}

class NetEaseLRCLyricWriter : LyricWriter {
    override fun writer(info: LyricInfo, output: OutputStream) {
        val writer = OutputStreamWriter(output, Charsets.UTF_8)
        if (info.title != null) {
            writer.appendln("[ti:${info.title}]")
        }
        if (info.album != null) {
            writer.appendln("[al:${info.album}]")
        }
        if (info.singer != null) {
            writer.appendln("[ar:${info.singer}]")
        }
        if (info.author != null) {
            writer.appendln("[au:${info.author}]")
        }

        info.timelines.forEach {
            writer.appendln("[${it.time}]${it.text}")
        }
        writer.flush()
    }

}

class NetEaseSRTLyricWriter : LyricWriter {

    private val parser = DateTimeFormatterBuilder()
        .appendPattern("mm:ss.SS")
        .toFormatter()

    private val formatter = DateTimeFormatterBuilder()
        .appendPattern("mm:ss,SSS")
        .toFormatter()

    override fun writer(info: LyricInfo, output: OutputStream) {
        val writer = OutputStreamWriter(output, Charsets.UTF_8)
        val timelines = info.timelines

        if (timelines.size > 1) {
            val first = timelines.listIterator()
            val other = timelines.listIterator()
            other.next()
            var index = 1
            while (first.hasNext() && other.hasNext()) {
                val timeSlice = first.next()
                writer.appendln(index.toString())

                val startTime = formatter.format(parser.parse(timeSlice.time))
                val endTime = formatter.format(parser.parse(other.next().time))

                writer.appendln("00:$startTime --> 00:$endTime")
                writer.appendln(timeSlice.text)
                writer.appendln()
                index++
            }

        }
        writer.flush()
    }

}